#include <iostream>
#include <string>
#include <assert.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <cstdio>
#include <cstring>

using namespace std;

int main()
{
    // 1. 创建管道
    // pipefd[0]:读端(0像嘴巴,读书)
    // pipefd[1]:写端(1像钢笔,写字)
    int pipefd[2] = {0};
    int n = pipe(pipefd);
    assert(n != -1);
    (void)n; // 避免Realease编译时出现大量告警

// 条件编译可以搭配命令行定义来进行debug
#ifdef DEBUG
    cout << "pipefd[0]:" << pipefd[0] << endl; // 3
    cout << "pipefd[1]:" << pipefd[1] << endl; // 4
#endif

    // 2. 创建子进程
    // fork创建子进程失败返回-1
    pid_t id = fork();
    assert(id != -1);
    if (id == 0)
    {
        // 关闭子进程不需要的fd,子进程进行读取
        close(pipefd[1]);
        char buffer[1024];
        while (true)
        {
            // 写入的一方，fd没有关闭，如果有数据，就读，没有数据就等
            // 写入的一方，fd关闭, 读取的一方，read会返回0，表示读到了文件的结尾！
            ssize_t s = read(pipefd[0], buffer, sizeof(buffer) - 1);
            if (s > 0)
            {
                buffer[s] = 0;
                cout << "child process[" << getpid() << "]" << "get a message, Fathe#" << buffer << endl;
            }
            else if(s == 0)
            {
                cout << "writer quit(father), me quit too!!!" << endl;
                break;
            }
        }
        // close(pipefd[0]); 
        exit(0);    // 进程退出,文件描述符会被关掉,不代表文件被关掉
    }

    // 关闭父进程不需要的fd,父进程进行写入
    close(pipefd[0]);
    string message = "我是父进程,我正在给你发消息";
    char send_buffer[1024];
    int count = 0;
    while (true)
    {
        // 构造变化的字符串
        snprintf(send_buffer, sizeof(send_buffer), "%s[%d] : %d", message.c_str(), getpid(), count++);
        write(pipefd[1], send_buffer, strlen(send_buffer));
        sleep(1);
        if(count == 5)
        {
            cout << "writer quit(father)" << endl;
            break;
        }
    }

    close(pipefd[1]);
    pid_t ret = waitpid(id, nullptr, 0);    // 阻塞等待
    assert(ret > 0);
    (void)ret;

    return 0;
}